package rabbitmq

import (
	"Shopping/settings"
	"fmt"
	"github.com/streadway/amqp"
	"go.uber.org/zap"
	"log"
	"sync"
	"time"
)

func Init(cfg *settings.RabbitMQConfig) (err error) {
	// 构建连接字符串
	connStr := fmt.Sprintf("amqp://%s:%s@%s:%d%s",
		cfg.User,
		cfg.Password,
		cfg.Host,
		cfg.Port,
		cfg.Vhost,
	)
	// 进行连接
	conn, err := amqp.Dial(connStr)
	if err != nil {
		zap.L().Error("connect RabbitMQ failed", zap.Error(err))
		return
	}
	// 这里可以根据需要进行进一步操作，例如创建通道等
	// 例如创建通道
	ch, err := conn.Channel()
	if err != nil {
		zap.L().Error("create RabbitMQ channel failed", zap.Error(err))
		return
	}
	// 关闭通道和连接，这里可以根据实际情况处理，例如在程序结束时再关闭，此处仅为示例
	time.Sleep(5 * time.Second)
	ch.Close()
	conn.Close()
	return
}

// rabbitMQ结构体
type RabbitMQ struct {
	conn    *amqp.Connection
	channel *amqp.Channel
	// 队列名称
	QueueName string
	// 交换机名称
	Exchange string
	// bind Key 名称
	Key string
	// 连接信息
	Mqurl string
	sync.Mutex
}

// 断开channel 和 connection
func (r *RabbitMQ) Destory() {
	r.channel.Close()
	r.conn.Close()
}

// 错误处理函数
func (r *RabbitMQ) failOnErr(err error, message string) {
	if err != nil {
		log.Fatalf("%s:%s", message, err)
		// panic(fmt.Sprintf("%s:%s", message, err))
	}
}

//// 创建简单模式下RabbitMQ实例
//func NewRabbitMQSimple(queueName string, cfg *settings.RabbitMQConfig) *RabbitMQ {
//	// 创建 RabbitMQ 实例
//	rabbitmq := NewRabbitMQ(queueName, "", "", cfg)
//	var err error
//	// 获取 connection
//	rabbitmq.conn, err = amqp091.Dial(rabbitmq.Mqurl)
//	rabbitmq.failOnErr(err, "failed to connect rabbitmq!")
//	// 获取 channel
//	rabbitmq.channel, err = rabbitmq.conn.Channel()
//	rabbitmq.failOnErr(err, "failed to open a channel")
//	return rabbitmq
//}

//// 直接模式队列生产
//func (r *RabbitMQ) PublishSimple(message string) error {
//	r.Lock()
//	defer r.Unlock()
//	// 1. 申请队列，如果队列不存在会自动创建，存在则跳过创建
//	_, err := r.channel.QueueDeclare(
//		r.QueueName,
//		// 是否持久化
//		false,
//		// 是否自动删除
//		false,
//		// 是否具有排他性
//		false,
//		// 是否阻塞处理
//		false,
//		// 额外的属性
//		nil,
//	)
//	if err != nil {
//		return err
//	}
//	// 调用 channel 发送消息到队列中
//	r.channel.Publish(
//		r.Exchange,
//		r.QueueName,
//		// 如果为 true，根据自身 exchange 类型和 routekey 规则无法找到符合条件的队列会把消息返还给发送者
//		false,
//		// 如果为 true，当 exchange 发送消息到队列后发现队列上没有消费者，则会把消息返还给发送者
//		false,
//		amqp.Publishing{
//			ContentType: "text/plain",
//			Body:        []byte(message),
//		})
//	return nil
//}
//
//// simple 模式下消费者
//func (r *RabbitMQ) ConsumeSimple(orderService logic.IOrderService, productService logic.IProductService) {
//	//1.申请队列，如果队列不存在会自动创建，存在则跳过创建
//	q, err := r.channel.QueueDeclare(
//		r.QueueName,
//		//是否持久化
//		false,
//		//是否自动删除
//		false,
//		//是否具有排他性
//		false,
//		//是否阻塞处理
//		false,
//		//额外的属性
//		nil,
//	)
//	if err != nil {
//		fmt.Println(err)
//	}
//
//	//消费者流控
//	r.channel.Qos(
//		1,     //当前消费者一次能接受的最大消息数量
//		0,     //服务器传递的最大容量（以八位字节为单位）
//		false, //如果设置为true 对channel可用
//	)
//
//	//接收消息
//	msgs, err := r.channel.Consume(
//		q.Name, // queue
//		//用来区分多个消费者
//		"", // consumer
//		//是否自动应答
//		//这里要改掉，我们用手动应答
//		false, // auto-ack
//		//是否独有
//		false, // exclusive
//		//设置为true，表示 不能将同一个Conenction中生产者发送的消息传递给这个Connection中 的消费者
//		false, // no-local
//		//列是否阻塞
//		false, // no-wait
//		nil,   // args
//	)
//	if err != nil {
//		fmt.Println(err)
//	}
//
//	forever := make(chan bool)
//	//启用协程处理消息
//	go func() {
//		for d := range msgs {
//			//消息逻辑处理，可以自行设计逻辑
//			log.Printf("Received a message: %s", d.Body)
//			message := &models.Message{}
//			err := json.Unmarshal([]byte(d.Body), message)
//			if err != nil {
//				fmt.Println(err)
//			}
//			//插入订单
//			_, err = orderService.InsertOrderByMessage(message)
//			if err != nil {
//				fmt.Println(err)
//			}
//
//			//扣除商品数量
//			err = productService.SubNumberOne(message.ProductID)
//			if err != nil {
//				fmt.Println(err)
//			}
//			//如果为true表示确认所有未确认的消息，
//			//为false表示确认当前消息
//			d.Ack(false)
//		}
//	}()
//
//	log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
//	<-forever
//}
